Public: Technology Reviews : Ruby on Rails
This page last changed on May 02, 2007 by scytacki.
Using Ruby on Rails at CCStart here: Ruby on Rails, the RoR API online. If you are using a Mac this article is useful: Building Ruby, Rails, Subversion, Mongrel, and MySQL on Mac OS X - there are some good reasons to rebuild Ruby from source. If the page won't load here's the Google cache: put the following into your ~/.irbrc file to enable tabbed completion: require 'irb/completion' ARGV.concat [TSC: "--readline", "--prompt-mode", "simple" ] Err the blog has a great article on more to add to irb for rails debugging: http://errtheblog.com/post/43 Some great rails blogs by some of the core rails developers: The best rails blog software: Mephisto. I keep a copy of Rails (released and edge), Mephisto, all of technoweenies plugins and why's code checked out of their subversion repositories and use them as reference to see how well designed rails and ruby code works. On Ruby There's a guy named "why the lucky stiff", his blog and code pages are also quite interesting: One of his projects is Hpricot: http://code.whytheluckystiff.net/hpricot/wiki Alternate Ruby web frameworks
Recommended BooksI recommend getting these books. I bought the combined paper and pdf – both forms are quite useful in different ways.
Misc Useful Tools
Rails PluginsTake a look at these two plugins for Rails. They are very uselful and very easy to use for a web application programmer. If you look under the hood they are also very interesting examples of Ruby code and the ease with which meta-programming can be done in Ruby and in Rails.
JRubyJRuby is an implementation of the Ruby VM in Java. Version 0.9.3 will shortly be released. Projects at ConcordHere's a list of the Rails microportals I've developed so far at CC: This is a simple Rails app. It allows you to create simple learning activities that get built into custom xml (otml) and passed to a the TEEMSS2 Java application SensorPortfolio through a custom jnlp builder. The development version of the TEEMSS2 DIY site which uses the SDS as for learner data persistence. The Seeing Math site is a simple variation of the TEEMSS2 site that delivers applets instead of Java webstart applications. Deprecated In July I wrote a variant that supports a SAIL-based TELS-PAS learner environment using a REST web services architecture. A simple REST-based services model is used to send data between the portal and the Java PAS Learner Runtime system. In addition to the REST based learner data turnaround the app is doing a great deal of xml hacking to create reports on learner interaction with rich models (I'll bet there are much better ways to accomplish what I want). See the Model Schemas link in this page: The Sail Data Service (SDS) Most of these apps use The Concord Consortium's General Members database (CCMembers) for user authentication. Setting up Rails on an Existing Serverolder content below ... needs editing and updating At Concord we have two main "web" servers, one for general pages and php/database applications, and another for project web applications. That was the server onto which we put the Rails setup. If you are using a package management system, like RPMs, it's pretty easy to get started. Install the most recent versions of Ruby, Rails, and Lighthttpd. Set up your apache to proxy through requests to Lighthttpd. Something like this: <VirtualHost \*:80 \*:8080> ServerAdmin webmaster@concord.org ServerName rails.dev.concord.org ProxyPass / [http://127.0.0.1:8580/] ProxyPassReverse / [http://127.0.0.1:8580/] ProxyTimeout 1200 ErrorLog /var/log/httpd/rails.dev.concord.org-error_log CustomLog /var/log/httpd/rails.dev.concord.org-access_log combined </VirtualHost> In the ProxyPass directive, you list whatever port your Lighthttpd server is running on. To enable HTTPS/SSL support, get an SSL certificate and add an additional virtual host to the apache configuration, like the following: <VirtualHost \*:443> ServerAdmin webmaster@concord.org ServerName rails.dev.concord.org SSLEngine on SSLCertificateFile /usr/share/ssl/certs/mycert.crt SSLCertificateKeyFile /usr/share/ssl/certs/mycert.key SSLCertificateChainFile /usr/share/ssl/certs/sf_issuing.crt ProxyPass / [http://127.0.0.1:8580/] ProxyPassReverse / [http://127.0.0.1:8580/] ProxyTimeout 1200 ErrorLog /var/log/httpd/rails-ssl.dev.concord.org-error_log CustomLog /var/log/httpd/rails-ssl.dev.concord.org-access_log combined </VirtualHost> Creating a Rails application from scratch and getting it onto the development server.I'm assuming you have ruby, gems, and mysql working on your computer. Updated StepsHere's what I do now to start an application calls rest: svn mkdir -m "creating app root dir in repository" svn+ssh://svn.rails.dev.concord.org/home/subversion/projects/trunk/common/rails/rest mysqladmin -u root -p****** create rest_development mysqladmin -u root -p****** create rest_test mysqladmin -u root -p****** create rest_production svn co svn+ssh://svn.rails.dev.concord.org/home/subversion/projects/trunk/common/rails/rest rails rest cd rest rmdir components mv config/database.yml config/database_sample.yml svn add config app db doc lib public script test vendor svn add --non-recursive log tmp svn propset svn:ignore '*' log tmp cp config/database_sample.yml config/database.yml svn propset svn:ignore 'database.yml' config svn add Rakefile README svn commit -m "initial check in" Then I use Piston to install Edge Rails and a series of plugins that will be needed: piston import http://dev.rubyonrails.org/svn/rails/trunk vendor/rails piston import http://dev.rubyonrails.com/svn/rails/plugins/ssl_requirement/ vendor/plugins/ssl_requirement piston import http://dev.rubyonrails.com/svn/rails/plugins/tzinfo_timezone/ vendor/plugins/tzinfo_timezone piston import http://dev.rubyonrails.com/svn/rails/plugins/tztime/ vendor/plugins/tztime piston import http://dev.rubyonrails.com/svn/rails/plugins/simply_helpful/ vendor/plugins/simply_helpful/ piston import http://svn.pragprog.com/Public/plugins/annotate_models vendor/plugins/annotate_models piston import http://svn.techno-weenie.net/projects/plugins/restful_authentication/ vendor/plugins/restful_authentication piston import http://svn.umesd.k12.or.us/plugins/query_analyzer vendor/plugins/query_analyzer svn commit -m "used piston to check in edge rails and plugins" Older InstructionsIn the directory you do web development open a shell and create the rails application: rails myapp cd myapp This creates a directory with the skeleton of a rails application. I use iTermbecause it supports multiple tabbed windows. I'll assume you are too. Open four tabbed shell windows and cd into myapp in all of them. Create the mysql databases: myapp_development and myapp_test. I also use Textmate($75) as a programming editor when I am doing Rails development. If you are using Textmate open the whole myapp folder by doing this in the shell: mate . Edit config/database.yml and enter the appropriate values for the database, username, and password: development: adapter: mysql host: localhost database: myapp_development username: root password: test: adapter: mysql database: myapp_test username: root password: Make a copy of this file in config/ without the passwords and label it databse_sample.yml. Don't worry about the production database for now. Normally you'd create a real application now but for this documentation I'm going to use scaffolds (they'll auto-generate the app) to hack together something very quickly. Select the first tab in iTerm and generate a simple model and database migration for something we'll call a page. script/generate model page exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/page.rb create test/unit/page_test.rb create test/fixtures/pages.yml create db/migrate create db/migrate/001_create_pages.rb Anytime you are using a generator you can suffix the command with --pretend to see what the generator will do without executing it. Edit the db/migrate/001_create_pages.rb as follows:
class CreatePages < ActiveRecord::Migration
def self.up
create_table :myapp_pages do |t|
t.column :name, :string
t.column :content, :text
end
end
def self.down
drop_table :myapp_pages
end
end
When you deploy this application to the development server your tables will be mixed in with all the other tables used by the various rails applications in the database rails on databse.concord.org. In order to keep the table names separate I prefix them with the application name in the migration file and the model. This isn't necessary on your local machine but it makes things simpler. Add this line to app/models/page.rb:
class Page < ActiveRecord::Base
set_table_name "myapp_pages"
end
One more detail is to set the relative url root (for use only on the deployment server) and to override the default schema_info_table_name with the application name prefix. Add this to config/environment.rb: # ActionController::AbstractRequest.relative_url_root = "/myapp" module ActiveRecord class Migrator def Migrator.schema_info_table_name Base.table_name_prefix + "myapp_schema_info" + Base.table_name_suffix end end end Now in the first shell tab run the rake task db:migrate to apply this migration to the myapp_development database and create the table pages. Rake is a Ruby version of Bash's make and Java's ant. rake db:migrate (in /Users/stephen/dev/rails/myapp) == CreatePages: migrating ===================================================== -- create_table(:myapp_pages) -> 0.0030s == CreatePages: migrated (0.0032s) ============================================ That created the table in the mysql database. You'll end up creating a sequence of migration files to create new tables or change existing tables. All of these table are under version control. When you checkout the code to a new server you can recreate the entire database schema by just running the rake migration task. You can also run migrations in reverse like this: rake db:migrate VERSION=0 (in /Users/stephen/dev/rails/myapp) == CreatePages: reverting ===================================================== -- drop_table(:myapp_pages) -> 0.2586s == CreatePages: reverted (0.2588s) ============================================ Now use a scaffold to create a default controller and views (you can get the built-in help by typing script/generate scaffold): script/generate scaffold page page exists app/controllers/ exists app/helpers/ create app/views/page exists test/functional/ dependency model exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/page.rb create test/unit/page_test.rb create test/fixtures/pages.yml create app/views/page/_form.rhtml create app/views/page/list.rhtml create app/views/page/show.rhtml create app/views/page/new.rhtml create app/views/page/edit.rhtml create app/controllers/page_controller.rb create test/functional/page_controller_test.rb create app/helpers/page_helper.rb create app/views/layouts/page.rhtml create public/stylesheets/scaffold.css The application is ready to start. Open the second shell tab and start the web server. script/server webrick => Booting WEBrick... => Rails application started on http://0.0.0.0:3000 => Ctrl-C to shutdown server; call with --help for options [2006-08-07 23:26:22] INFO WEBrick 1.3.1 [2006-08-07 23:26:22] INFO ruby 1.8.4 (2005-12-24) [TSC:i686-darwin8.6.1] [2006-08-07 23:26:22] INFO WEBrick::HTTPServer#start: pid=1919 port=3000 You can check this window later to see what requests have been served. Open a browser and browse to: http://localhost:3000/. You'll see a static rails page titled: "Ruby on Rails: Welcome aboard". This page is nothing special and normally you'd delete it before going much further but we haven't created a route for "/" yet so don't do anything. There is some useful info here, click About your application's environment. You created a controller called page so try *http://localhost:3000/page*. You should see this: Click on New Page. enter some data for the fields: Name and Content and click the Create button. You should now have a listing of one page item. Select the third shell tab and open the an IRB session for the application: script/console Loading development environment. >> This is running an IRB (interactive ruby) session with all of your rails classes and models. Try this: Page.create(:name => "Another page", :content => "This is more stuff to write") => #<Page:0x27598f0 @new_record=false, @errors=#<ActiveRecord::Errors:0x2758338 @errors={}, @base=#<Page:0x27598f0 ...>>, @attributes={"name"=>"Another page", "id"=>2, "content"=>"This is more stuff to write"}> >> Page.find(:all).each { |p| puts p.name } test page Another page => [#<Page:0x2751a60 @attributes={"name"=>"test page", "id"=>"1", "content"=>"And this is the content"}>, #<Page:0x2751a24 @attributes={"name"=>"Another page", "id"=>"2", "content"=>"This is more stuff to write"}>] I created another Page object and saved it to the database. Then I iterated through all the Page objects passing each in turn to the code block delimited with '{ }' and printed the name attribute. Go back to the browser and click refresh. You should see two page objects. If you make changes in the source use reload! to load the new classes the console. In the fourth shell tab start a breakpoint service:
script/breakpointer
No connection to breakpoint service at druby://localhost:42531 (DRb::DRbConnError)
Tries to connect will be made every 2 seconds...
Now open app/controllerspage_controller.rb and enter a breakpoint at the start of the show method: def show breakpoint @page = Page.find(params[TSC::id]) end Now in the browser click the Show link for the first page. The browser should pause while loading the page, Take a look in the breakpointer shell:
Executing break point at ./script/../config/../app/controllers/page_controller.rb:16 in `show'
irb(#<PageController:0x26d5460>):001:0>
You can inspect and change variables, execute object methods, even redefine classes. In the example below I am inspecting the params hash, looking at the page object it is going to be used to reference and then chaging the id value of the hash and exiting the breakpoint irb session. Executing break point at ./script/../config/../app/controllers/page_controller.rb:16 in `show' irb(#<PageController:0x26d5460>):001:0> params => {"action"=>"show", "id"=>"1", "controller"=>"page"} irb(#<PageController:0x26d5460>):002:0> @page = Page.find(params[TSC::id]) => #<Page:0x2762cc0 @attributes={"name"=>"test page", "id"=>"1", "content"=>"And this is the content"}> irb(#<PageController:0x26d5460>):003:0> params[TSC::id] => "1" irb(#<PageController:0x26d5460>):004:0> params[TSC::id]=2 => 2 irb(#<PageController:0x26d5460>):005:0> exit Server exited. Closing connection... No connection to breakpoint service at druby://localhost:42531 (DRb::DRbConnError) Tries to connect will be made every 2 seconds... The browser will now display the second page object. Notice how the params hash related to the url. This is the url the browser tried to load: http://localhost:3000/page/show/1 - page is the controller, show is the method, and 1is the :id. In the breakpoint session we changed the value of :id to 2 and this is the page object the browser rendered instead. Now use the instructions here Using Subversion at CCto import your application to a subversion repository. There are a number of steps you need to take before doing the initial import. There are a number of files in the rails application directory which you don't want to copy. This blog article has a good overview: http://blog.teksol.info/articles/2006/03/09/subversion-primer-for-rails-projects Don't add these files, instead copy them manually to the development server. The file database.yml has the database passwords so you don't ever want to check this in to any repository which might be publically accesible. These files will also need to be edited before the deployment will work. config/database.yml config/environment.rb If you accidently added these files to subversion before you commit them you can reverse this operation with the revert command: svn revert config/database.yml svn revert config/environment.rb If your Rails app is up and working first make copies of these files: cp config/database.yml config/database.yml.sample cp config/environment.rb config/environment.rb.sample Then remove the passwords from the sample files and add them to subversion. This will give anyone who chacks out a copy of the project a good template to start from. Don't add these files either - you don't want these managed by subversion. The log files are written to by LightTPD the web server and db/schema.rb is managed by running the migrations on the server. svn propset svn:ignore "*.log" log svn propset svn:ignore "schema.db" db svn propset svn:ignore "*" tmp/sessions tmp/cache tmp/sockets svn propset svn:ignore "*" tmp svn propset svn:ignore "database.yml" config svn propset svn:ignore "environment.rb" config I had trouble with the last two. They seemed to overwrite each other. Try adding the files in config/ to ignore using your editor with this command: svn propedit svn:ignore config If you are on a Mac you should also have svn ignore the '.DS_Store' it scatters in directories for use in caching the finder settings. You can set global ignore settings for svn in you ~/.subversion folder.
svn propset svn:ignore -R ".DS_Store"
When you create a bunch of new files which need to be added to subversion you can use the following shell command to add every file whose subversion status is '?':
svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add
If you use this command frequently add it to your .bash_profile as an alias:
alias svnaddall=svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add
Checkout on the serverRight now the rails development server and the subversion server are on the same host so you can use a file type url to reference the repository location. The advantage is that if you won't be asked for your password when doing checkouts or commits.
cd /web/rails.dev.concord.org/
svn file:///home/subversion/myapp/trunk myapp
This will checkout a copy of the trunk from the myapp subversion repository. Reset the permissions on myapp/log to allow the web server to create and write it's log files: cd myapp chmod 777 log Recreate the files db/database.yml and config/environment.rb. Edit the lighttpd.conf file and just copy one of the other rails app blocks and replace the app name with myapp. You will need sudo access to edit this file. sudo emacs /etc/lighttpd/lighttpd.conf Now restart lighttpd. sudo /etc/rc.d/init.d/lighttpd restart
database.sample.yml (application/octet-stream)
|
Document generated by Confluence on Jan 27, 2014 16:56 |